// 你这个学期必须选修 numCourses 门课程，记为 0 到 numCourses - 1 。

// 在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出，其中 prerequisites[i] = [ai, bi] ，表示如果要学习课程 ai 则 必须 先学习课程  bi 。

// 例如，先修课程对 [0, 1] 表示：想要学习课程 0 ，你需要先完成课程 1 。
// 请你判断是否可能完成所有课程的学习？如果可以，返回 true ；否则，返回 false 。

// 来源：力扣（LeetCode）
// 链接：https://leetcode-cn.com/problems/course-schedule
// 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。

// 看了题解
// 拓扑排序

// 执行用时：
// 20 ms
// , 在所有 C++ 提交中击败了
// 84.35%
// 的用户
// 内存消耗：
// 13 MB
// , 在所有 C++ 提交中击败了
// 69.51%
// 的用户

#include<bits/stdc++.h>
#include<string>
#include<vector>
#include<list>
#include<unordered_map>
#include<set>
#include<queue>
using namespace std;

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        int n = prerequisites.size();
        // 无先修则直接满足
        if(n==0){
            return true;
        }
        // 每门课的先修课程数量
        vector<int> indegree(numCourses);
        // 先修课程，后续课程
        vector<vector<int>> adj(numCourses);
        // 可修课程
        queue<int> help;
        for(int i=0;i<n;i++){
            indegree[prerequisites[i][0]]++;
            adj[prerequisites[i][1]].push_back(prerequisites[i][0]);
        }
        // 无先修
        for(int i=0;i<indegree.size();i++){
            if(indegree[i]==0){
                help.push(i);
            }
        }
        int cnt =0;
        while (!help.empty()){
            int course = help.front();
            help.pop();
            cnt++;
            for(int i=0;i<adj[course].size();i++){
                indegree[adj[course][i]]--;
                if(indegree[adj[course][i]]==0){
                    help.push(adj[course][i]);
                }
            }
            
        }
        return cnt==numCourses;
    }
};